__author__ = 'Muscle'

import ctypes
import time

from mui.muievent import *
from mui.CExt.CUser32 import *
import mui.InternalUse.clock as clock
import traceback
USER_TIMER_MAXIMUM = 0x7FFFFFFF

class muiWin32EventLoop(MUIEventDispatcher):

    windows = set()
    has_exit = False
    def __init__(self):
        MUIEventDispatcher.__init__(self)

    def __del__(self):
        pass

    def run(self):
        self._timer = timer = SetPyTimer(0, 0, self._timer_func)
        self._polling = True
        self._allow_polling = True
        msg = MSG()

        self.dispatch_event('on_enter')
        while not self.has_exit:
            if self._polling:
                while CPeekMessage(msg,
                                           0, 0, 0, PM_REMOVE):
                    CTranslateMessage(msg)
                    CDispatchMessage(msg)

                self._timer_func( timer, 0)

            else:
                CGetMessage(msg, 0, 0, 0)
                CTranslateMessage(msg)
                CDispatchMessage(msg)

                # Manual idle event
                msg_types = GetQueueStatus(QS_ALLINPUT) & 0xffff0000
                if (msg.message != WM_TIMER and
                    not msg_types & ~(QS_TIMER<<16)):
                    self._timer_func( timer, 0)
            
        self.dispatch_event('on_exit')

    def run_domodal(self, dlg):
        try:
            from mui.Widgets.muidialog import PopupBase
            from mui.muicomponent import IWindow
            assert (isinstance(dlg, PopupBase))
            dlgHwnd = None
            if (isinstance(dlg, IWindow)):
                dlgHwnd = dlg.getHwnd()
            timer = self._timer
            msg = MSG()

            self._polling = True #clear message immediately
            
            while not self.has_exit and not dlg.breakLoop:
                if self._polling:
                    while CPeekMessage(msg, 0, 0, 0, PM_REMOVE):
                        CTranslateMessage(msg)
                        CDispatchMessage(msg)
                    self._timer_func( timer, 0)

                else:
                    CGetMessage(msg, 0, 0, 0)
                    CTranslateMessage(msg)
                    CDispatchMessage(msg)

                    msg_types = GetQueueStatus(QS_ALLINPUT) & 0xffff0000
                    if (msg.message != WM_TIMER and
                        not msg_types & ~(QS_TIMER<<16)):
                        self._timer_func( timer, 0)
        except Exception, e:
            traceback.print_exc()
            return None

    def _idle_chance(self):
        if (self._next_idle_time is not None and
            self._next_idle_time <= time.time()):
            self._timer_func(0, 0, self._timer, 0)

    def idle(self):
        dt = clock.tick(True)
        # Redraw all windows
        for window in self.windows:
            window.dispatch_event('on_paint')

        # Update timout
        return clock.get_sleep_time(True)

    def _timer_func(self, timer, t):

        sleep_time = self.idle()

        if sleep_time is None:
            # Block indefinitely

            millis = USER_TIMER_MAXIMUM
            self._next_idle_time = None
            self._polling = False
            SetPyTimer(timer, millis, self._timer_func)

        elif sleep_time < 0.01 and self._allow_polling:
            # Degenerate to polling
            millis = USER_TIMER_MAXIMUM
            self._next_idle_time = 0.
            if not self._polling:
                self._polling = True
                SetPyTimer(timer, millis, self._timer_func)
        else:
            # Block until timer
            # XXX hack to avoid oversleep; needs to be api
            sleep_time = max(sleep_time - 0.01, 0)
            millis = int(sleep_time * 1000)
            self._next_idle_time = time.time() + sleep_time
            self._polling = False
            SetPyTimer(timer, millis, self._timer_func)


    def exit(self):
        self.has_exit = True

    def on_window_close(self, window):
        self.windows.remove(window)
        if not self.windows:
            self.exit()
def run():
    g_muiApp.run()

def run_domodal(dlg):
    g_muiApp.run_domodal(dlg)

def getEventLoop():
    return g_muiApp

g_muiApp = muiWin32EventLoop()